package com.agent.tools;

import com.agent.config.CalendarConfig;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import java.time.Duration;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
    日期/日历工具：通过聚合数据 日历 API 查询某日的节假日、农历、宜忌等。

    功能说明：
        - 支持获取当前日期信息
        - 支持查询指定日期的日历详情（节假日/农历/宜忌等）
        - 配合大模型实现模糊时间表达的解析和转换

    使用场景示例：
        用户输入："我想查下个月的第一个周五是几号"
            处理流程：
            1. 调用 currentDay() 获取当前日期作为参考
            2. 大模型根据当前日期推理出"下个月的第一个周五"对应的具体日期
            3. 调用 calendarDay() 查询该日期的详细信息

    支持的模糊时间表达包括但不限于：
        - 相对时间：下周、下个月、明年、上周、上个月、去年等
        - 星期表达：下周三、上周五、本月最后一个周日等
        - 年度表达：今年、去年、明年等
 */

@Component("calendarTools")
@RequiredArgsConstructor
public class CalendarTools {

    private final CalendarConfig calendarConfig;
    private final WebClient webClient = WebClient.builder().build();

    /*
    * 查询当前年-月-日时间信息
     */
    @Tool(name = "current_day_info", value = "当用户提出模糊时间概念时（如\"下周\"、\"下个月\"、\"明年\"、\"上周三\"、\"今年\"、\"去年\"等），\n" +
            "先调用此工具获取当前确切日期，再结合自然语言推理出具体日期（格式：yyyy-M-dd）和星期")
    public String currentDay(){
        // 获取当前时间
        LocalDate currentDate  = LocalDate.now();
        // 日期格式转换，yyyy-M-dd格式匹配聚合数据 api 所需参数
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-M-dd");
        // 获取星期几 (1=星期一, 2=星期二, ..., 7=星期日)
        int dayOfWeek = currentDate.getDayOfWeek().getValue();
        // 星期几的中文表示
        String[] weekDays = {"", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};

        return "当前时间：" + currentDate.format(dateTimeFormatter) + "，" + weekDays[dayOfWeek];
    }

    /**
     * 查询指定日期的日历信息
     */
    @Tool(name = "calendarDay", value = "（用户没明说查询详细信息时，可不调用此工具）查询指定日期的详细日历信息，包括节假日、农历、生肖、宜忌等。参数：date，格式为 yyyy-M-dd。")
    public String calendarDay(@P(value = "日期，格式为 yyyy-M-dd") String date) {
        /*
        调用聚合数据日历API查询指定日期的日历信息
            1.检验了是否传入参数和apikey，如果未配置则返回错误信息
            2.构建请求URL，调用聚合数据日历API
            3.用weClient工具类发起请求
            4.解析数据，返回结果
         */
        if (date == null || date.isBlank()) {
            return "请提供日期（yyyy-MM-dd）";
        }
        if (calendarConfig.getKey() == null || calendarConfig.getKey().isBlank()) {
            return "未配置聚合数据日历API Key";
        }
        try {
            String url = String.format("http://v.juhe.cn/calendar/day?date=%s&key=%s", encode(date), calendarConfig.getKey());
            System.out.println("请求聚合数据日历API：" + url);
            String json = webClient.get().uri(url) // 通过URL发起get请求
                    .retrieve() // 发起请求并准备获取响应
                    .bodyToMono(String.class) // 将响应体转换为Mono<String>类型，即异步获取响应的字符串内容
                    .timeout(Duration.ofSeconds(8)) // 设置请求超时时间为8秒，如果超过这个时间未收到响应则会触发超时异常
                    .onErrorReturn("{\"error\":\"请求超时或网络错误\"}") // 异常处理：当发生任何错误（包括超时、网络异常等）时，返回默认的错误信息
                    .block(); // 阻塞等待异步操作完成，并获取最终结果。将异步的Mono<String>转换为同步的String结果
            if (json == null) return "查询日历失败（网络或API错误）";
//            return JuheJson.formatCalendar(json);
            System.out.println("聚合数据日历API返回：" + json);
            return json;
        } catch (Exception e) {
            return "查询日历时发生异常：" + e.getMessage();
        }
    }

    /**
     * URL编码, 解决中文乱码
     */
    private String encode(String s) {
        try { return java.net.URLEncoder.encode(s, java.nio.charset.StandardCharsets.UTF_8); } catch (Exception e) { return s; }
    }

}
